package server

import (
	"context"
	"errors"
	"fmt"
	"longmen/server/config/global"
	global2 "longmen/server/config/global"
	publisher2 "longmen/server/internal/services/consumers/publisher"
	_const "longmen/server/pkg/common/helper/const"
	"longmen/server/pkg/common/helper/encrypt"
	string2 "longmen/server/pkg/common/helper/string"
	time2 "longmen/server/pkg/common/helper/timehelper"
	"longmen/server/pkg/common/helper/util"
	"longmen/server/pkg/common/sdk"
	"longmen/server/pkg/db/mysql"
	"longmen/server/pkg/db/mysql/db_main"
	"longmen/server/pkg/db/mysql/models/models_main"
	"longmen/server/pkg/db/redis/cache"
	pb "longmen/server/pkg/protobuf"
	"regexp"
	"strings"
	"time"

	"longmen/server/pkg/common/api_models"

	"github.com/spf13/cast"
)

var accountRx = regexp.MustCompile("^[a-zA-Z0-9_-]{6,32}$")

func (s *Server) Regist(ctx context.Context, req *pb.CheckVerifyCodeReq) (*pb.CheckVerifyCodeResp, error) {
	acc, _ := s.GetUser(map[string]interface{}{"mobile": req.GetMobile()})
	if acc.Id > 0 {
		if acc.Status == _const.ACCOUNT_DEACTIVED && acc.DeactiveTime.Before(time.Now()) { //如果时间早于now，说明销户了
			acc.Account = "_DEL_" + acc.Account + "_DEL_" //已删除的账号再也不会用了，加上前缀可以防止改索引拖累全世界
			acc.Mobile = "_DEL_" + acc.Mobile + "_DEL_"
			mysql.UpdateXAnyParam(nil, []string{"account", "mobile"}, acc, "update del user")
		} else {
			return nil, errors.New("手机号已存在")
		}
	}
	err := s.CheckCode(req.GetMobile(), req.GetSmscode())
	if err != nil {
		return nil, err
	}
	err = util.CheckMobile(req.Mobile)
	if err != nil {
		return nil, err
	}
	mobileHash := encrypt.GenHashWithLength(11)
	rHash := cache.GetMobileToHash(req.GetMobile())
	if len(rHash) > 1 {
		_ = cache.DelRegisterVerify(rHash)
	}
	err = cache.SetRegisterVerify(mobileHash, req.GetMobile())
	if err != nil {
		return nil, errors.New("设置验证缓存错误")
	}
	return &pb.CheckVerifyCodeResp{MobileHash: mobileHash}, nil
}

func (s *Server) ExecRegister(ctx context.Context, req *pb.RegisterReq) (*pb.RegisterResp, error) {
	var (
		err              error
		mobile, password string
		token, _         = encrypt.TokenWebDesECBEncrypt()
		condition        = map[string]interface{}{
			"account": req.GetAccount(),
		}
	)
	req.Account = strings.ReplaceAll(req.Account, " ", "")
	if mobile, err = cache.GetRegisterVerify(req.GetMobileHash()); err != nil {
		return nil, errors.New("验证码已过期,请重新注册")
	}

	if !accountRx.MatchString(req.Account) {
		global2.Log.Debugf("CCC账号含有不合法字符:%v", req.Account)
		return nil, errors.New("CCC账号含有不合法字符")
	}
	acc, _ := s.GetUser(condition)
	if acc.Id > 0 {
		if acc.Status == _const.ACCOUNT_DEACTIVED && acc.DeactiveTime.Before(time.Now()) { //如果时间早于now，说明销户了
			acc.Account = "_DEL_" + acc.Account + "_DEL_" //已删除的账号再也不会用了，加上前缀可以防止改索引拖累全世界
			acc.Mobile = "_DEL_" + acc.Mobile + "_DEL_"
			mysql.UpdateXAnyParam(nil, []string{"account", "mobile"}, acc, "update del user")
		} else {
			return nil, errors.New("账号已存在")
		}
	}
	user := &models_main.User{}
	user.Account = req.GetAccount()
	user.Mobile = mobile
	if req.GetPwd() != "" {
		password, err = encrypt.PwdDesECBEncrypt(req.GetAccount(), req.GetPwd())
		if err != nil {
			return nil, err
		}
		user.Password = password
	}

	user.RegistIp = req.GetIp()
	if req.Platform == 0 {
		user.TokenWeb = token
	} else {
		user.Token = token
	}
	user.RegistTime = time.Now()
	user.LastLogin = time.Now()
	user.LastIp = req.Ip
	user.LoginPlatform = int(req.GetPlatform())
	user.OnlineStatus = _const.ACCOUNT_ONLINE_STATUS_ONLINE
	user.RegistType = int(req.GetPlatform()) + 1
	user.DeviceInfo = req.DeviceInfo
	avatars, err := s.GetDefultAvatars(ctx, &pb.GetDefultAvatarsReq{Role: 1}) //1 for 普通用户
	if err == nil && len(avatars.DefultAvatar) >= 2 {
		rand := string2.RandInt(0, len(avatars.DefultAvatar)-1)
		user.Avatar = avatars.DefultAvatar[rand].ImageUrl
	}
	if req.GetPlatform() == _const.LOGIN_PLATFORM_WEB || req.GetPlatform() == _const.LOGIN_PLATFORM_H5 { //PC
		user.RegSourceId = cache.GetSourceIdByUrl(req.Website)
	} else {
		user.RegSourceId = req.GetRegSourceId() //other
	}

	if err = s.Register( //--------在这里写库-----------
		user,
		int(req.GetPlatform()),
		int(req.GetSex()),
		req.GetInviteCode()); err != nil {
		return nil, err
	}
	if user.RegSourceId != "" {
		err = global2.PublishChannelStats.Send(publisher2.RegisterChannelStats, user)
		global2.Log.Debugf("渠道号挂载,user_id:%v,RegSourceId:%v,err:%v", user.Id, user.RegSourceId, err)
		if err != nil {
			global2.Log.Errorf("Nats publish chanel %s", err.Error())
		}

	}

	_ = cache.DelRegisterVerify(req.GetMobileHash())

	if err = cache.SetUserToken(user.Id, token, int(req.GetPlatform())); err != nil {
		global2.Log.Errorf("set token error[%v]: ", err)
	} else {
		//加入過濾器
		_, err = global2.BloomAdd(global2.BLOOM_MOBILE, mobile)
		if err != nil {
			global2.Log.Errorf("set bloom MOBILE error[%v]: ", err)
		}
		_, err = global2.BloomAdd(global2.BLOOM_ID, cast.ToString(user.Id))
		if err != nil {
			global2.Log.Errorf("set bloom ID error[%v]: ", err)
		}

		//imsdk2.GetSdk().AddTags([]string{cast.ToString(user.Id)}, []string{imsdk2.NOTIFY_START_LIVE, imsdk2.NOTIFY_START_MATCH})
		loginReq := &api_models.LoginReq{ //注册后的登陆算一次登陆
			Ip:            req.GetIp(),
			LoginPlatform: int(req.Platform),
		}
		err = GenUserLog(user, loginReq, req.DeviceInfo)
		if err != nil {
			return nil, err
		}
	}

	if req.AnchorId > 0 {
		db_main.SetUserRecommendInc(int64(user.Id), req.AnchorId)
	}

	regReport(req.DeviceInfo, user.RegistIp, req.RegSourceId) //注册上报
	//cache.PushAny(api_models.PubFinishedActivity{Category: util.RegActivityType, Uid: user.Id}, util.ACTIVITY_EVENT_CHANNEL)
	err = global2.PublisherActivity.Send(publisher2.Activity, api_models.PubFinishedActivity{
		Category: _const.RegActivityType,
		Uid:      user.Id,
	})
	if err != nil {
		global2.Log.Errorf("err : %v", err)
	}
	return &pb.RegisterResp{
		Id:      int32(user.Id),
		Account: user.Account,
		//Token:    user.Token,
		//TokenWeb: user.TokenWeb,
		Token:    token,
		TokenWeb: token,
		NickName: user.NickName,
		Avatar:   user.Avatar,
	}, nil
}

// 注册的第二步
func (s *Server) Register(user *models_main.User, platform int, sex int, promoterCode string) error {
	uid, err := encrypt.Base34ToNum([]byte(promoterCode)) //推广人
	if err != nil {
		global2.Log.Errorf("Register promoterCode err:%v", err)
	}

	global2.Log.Debugf("###################pl-uid:%d,promoterCode:%v", uid, promoterCode)
	tx := global2.GetX().Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()
	err = tx.Error
	if err != nil {
		return err
	}
	user.Agentid = int(uid)                          //推广人ID
	err = db_main.InsertUserByTransactions(tx, user) //写入注册数据
	if err != nil {
		return err
	}
	if err := tx.Commit().Error; err != nil {
		return err
	}

	tx2 := global2.GetX().Begin()
	defer func() {
		if r := recover(); r != nil {
			tx2.Rollback()
		}
	}()
	err = tx2.Error
	if err != nil {
		return err
	}

	// 构建统计资料
	statistics := &models_main.Statistics{
		Id:   time.Now().Format(time2.TIME_LAYOUT_FORMAT_3),
		Time: time.Now(),
	}
	updateCol := "regist_pc" //待更新的字段
	switch platform {
	case 0:
		statistics.RegistPc = 1
		updateCol = "regist_pc"
	case 1: //ios
		statistics.RegistIos = 1
		updateCol = "regist_ios"
	case 2: //android
		statistics.RegistAndroid = 1
		updateCol = "regist_android"
	}

	// 更新统计
	err = db_main.UpdateStatisticsByTransactions(tx2, statistics.Id, updateCol, statistics)
	if err != nil {

		return err
	}

	// 更新用户资料
	profile := &models_main.UserProfile{Uid: user.Id, Gender: sex}
	err = db_main.InsertUserProfileByTransactions(tx2, profile)
	if err != nil {
		return err
	}

	// 用户成为agent
	err = db_main.InsertAgent(&models_main.Agent{
		Uid:        uint(user.Id),                         //注册的用户ID
		InviteCode: string(encrypt.Base34(uint(user.Id))), //注册用户的推广码
	})
	if err != nil {
		tx2.Rollback()
		return err
	}

	if promoterCode != "" {
		//写入推广关系表
		err = db_main.InsertUserPromoteByTx(tx2, &models_main.UserPromote{
			RefererId: uid,
			Uid:       uint(user.Id),
		})
		if err != nil {
			return err
		}
		////查推广人推广收益
		agent, err := db_main.GetAgentByUid(uid) //推广人的uid
		if err != nil {
			tx2.Rollback()
			return err
		}
		if agent.Id > 0 {
			//	//更新收益
			agent.Diamond += 10000 //加100克拉（约定，单位分）
			if err := db_main.UpdateAgentByTransactions(tx2, agent); err != nil {
				return err
			}
		}
	}
	if err := tx2.Commit().Error; err != nil {
		return err
	}
	/*------------===End of tx2===------------*/
	//修改注册人的昵称
	user.NickName = fmt.Sprintf("%s-%d", global2.Config.GetString("sysNickname"), user.Id)
	if err := db_main.UpdateUser([]string{"nick_name"}, user); err != nil {
		return err
	}
	return nil
}

// 注册上报
func regReport(imei, clientIp, regId string) {
	return
	//注册上报
	global2.Log.Debugf("imei:%s,regId:%s", imei, regId)
	if len(imei) > 1 {
		switch regId {
		case "xiaomi":
			err := sdk.ReportApiEmi(encrypt.Md5(imei), clientIp)
			if err != nil {
				global2.Log.Errorf("小米注册上报失败,err:%v", err)
			}
		}
	}
}

// 简化注册密码注册
func (s *Server) SimpleRegister(ctx context.Context, req *pb.RegisterReq) (*pb.RegisterResp, error) {
	var (
		err       error
		password  string
		token, _  = encrypt.TokenWebDesECBEncrypt()
		condition = map[string]interface{}{
			"account": req.GetAccount(),
		}
	)

	if !accountRx.MatchString(req.Account) {
		return nil, errors.New(global.Lang.T("account_contains_illegal_characters"))
	}
	acc, _ := s.GetUser(condition)
	if acc.Id > 0 {
		if acc.Status == _const.ACCOUNT_DEACTIVED && acc.DeactiveTime.Before(time.Now()) { //如果时间早于now，说明销户了
			acc.Account = "_DEL_" + acc.Account + "_DEL_" //已删除的账号再也不会用了，加上前缀可以防止改索引拖累全世界
			acc.Mobile = "_DEL_" + acc.Mobile + "_DEL_"
			mysql.UpdateXAnyParam(nil, []string{"account", "mobile"}, acc, "update del user")
		} else {
			return nil, errors.New(global.Lang.T("account_not_available"))
		}
	}
	user := &models_main.User{}
	user.Account = req.GetAccount()
	user.Mobile = req.GetAccount()
	if req.GetPwd() != "" {
		password, err = encrypt.PwdDesECBEncrypt(req.GetAccount(), req.GetPwd())
		if err != nil {
			return nil, err
		}
		user.Password = password
	}

	user.RegistIp = req.GetIp()
	if req.Platform == 0 {
		user.TokenWeb = token
	} else {
		user.Token = token
	}
	user.RegistTime = time.Now()
	user.LastLogin = time.Now()
	user.LastIp = req.Ip
	user.LoginPlatform = int(req.GetPlatform())
	user.OnlineStatus = _const.ACCOUNT_ONLINE_STATUS_ONLINE
	user.RegistType = int(req.GetPlatform()) + 1
	user.DeviceInfo = req.DeviceInfo
	avatars, err := s.GetDefultAvatars(ctx, &pb.GetDefultAvatarsReq{Role: 1}) //1 for 普通用户
	if err == nil && len(avatars.DefultAvatar) >= 2 {
		rand := string2.RandInt(0, len(avatars.DefultAvatar)-1)
		user.Avatar = avatars.DefultAvatar[rand].ImageUrl
	}
	if req.GetPlatform() == _const.LOGIN_PLATFORM_WEB || req.GetPlatform() == _const.LOGIN_PLATFORM_H5 { //PC
		user.RegSourceId = cache.GetSourceIdByUrl(req.Website)
	} else {
		user.RegSourceId = req.GetRegSourceId() //other
	}

	if err = s.Register( //--------在这里写库-----------
		user,
		int(req.GetPlatform()),
		int(req.GetSex()),
		req.GetInviteCode()); err != nil {
		return nil, err
	}

	if err = cache.SetUserToken(user.Id, token, int(req.GetPlatform())); err != nil {
		global2.Log.Errorf("set token error[%v]: ", err)
	} else {
		//加入過濾器
		_, err = global2.BloomAdd(global2.BLOOM_MOBILE, user.Mobile)
		if err != nil {
			global2.Log.Errorf("set bloom MOBILE error[%v]: ", err)
		}
		_, err = global2.BloomAdd(global2.BLOOM_ID, cast.ToString(user.Id))
		if err != nil {
			global2.Log.Errorf("set bloom ID error[%v]: ", err)
		}

		//imsdk2.GetSdk().AddTags([]string{cast.ToString(user.Id)}, []string{imsdk2.NOTIFY_START_LIVE, imsdk2.NOTIFY_START_MATCH})
		loginReq := &api_models.LoginReq{ //注册后的登陆算一次登陆
			Ip:            req.GetIp(),
			LoginPlatform: int(req.Platform),
		}
		err = GenUserLog(user, loginReq, req.DeviceInfo)
		if err != nil {
			return nil, err
		}
	}
	if user.RegSourceId != "" {
		err = global2.PublishChannelStats.Send(publisher2.RegisterChannelStats, user)
		if err != nil {
			global2.Log.Errorf("渠道号挂载 Nats publish chanel %s", err.Error())
		}

	}
	if req.AnchorId > 0 {
		db_main.SetUserRecommendInc(int64(user.Id), req.AnchorId)
	}

	regReport(req.DeviceInfo, user.RegistIp, req.RegSourceId) //注册上报
	//cache.PushAny(api_models.PubFinishedActivity{Category: util.RegActivityType, Uid: user.Id}, util.ACTIVITY_EVENT_CHANNEL)
	err = global2.PublisherActivity.Send(publisher2.Activity, api_models.PubFinishedActivity{
		Category: _const.RegActivityType,
		Uid:      user.Id,
	})
	if err != nil {
		global2.Log.Errorf("err : %v", err)
	}
	return &pb.RegisterResp{
		Id:      int32(user.Id),
		Account: user.Account,
		//Token:    user.Token,
		//TokenWeb: user.TokenWeb,
		Token:    token,
		TokenWeb: token,
		NickName: user.NickName,
		Avatar:   user.Avatar,
	}, nil
}
